// 11_traits.rs
// Rust Trait 教程

use std::fmt;

// 1. 定义 Trait
pub trait Summary {
    fn summarize(&self) -> String;
    
    // 5. 默认实现
    fn summarize_author(&self) -> String {
        format!("@{}", self.summarize())
    }
}

// 2. 在类型上实现 Trait
#[derive(Debug)]
pub struct NewsArticle {
    pub headline: String,
    pub location: String,
    pub author: String,
    pub content: String,
}

impl fmt::Display for NewsArticle {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.headline)
    }
}

impl Summary for NewsArticle {
    fn summarize(&self) -> String {
        format!("{}, by {} ({})", self.headline, self.author, self.location)
    }
}

#[derive(Debug)]
pub struct Tweet {
    pub username: String,
    pub content: String,
    pub reply: bool,
    pub retweet: bool,
}

impl fmt::Display for Tweet {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        print!("{}", "[Tweet fmt] ");
        write!(f, "{}", self.username)
    }
}

impl Summary for Tweet {
    fn summarize(&self) -> String {
        format!("{}: {}", self.username, self.content)
    }
    
    // 5. 覆盖默认实现
    fn summarize_author(&self) -> String {
        format!("@{}", self.username)
    }
}

fn main() {
    // 3. 调用 Trait 方法
    let tweet = Tweet {
        username: String::from("horse_ebooks"),
        content: String::from("of course, as you probably already know, people"),
        reply: false,
        retweet: false,
    };
    
    println!("1 个新的name: {}", tweet);
    println!("1 个新的推文: {}", tweet.summarize());
    
    // 4. 默认实现
    println!("推文作者: {}", tweet.summarize_author());
    
    let article = NewsArticle {
        headline: String::from("Penguins win the Stanley Cup Championship!"),
        location: String::from("Pittsburgh, PA, USA"),
        author: String::from("Iceburgh"),
        content: String::from("The Pittsburgh Penguins once again are the best hockey team in the NHL."),
    };
    
    println!("新的文章可用! {}", article.summarize());
    println!("文章作者: {}", article.summarize_author());
    
    // 6. Trait 作为参数
    notify(&article);
    notify(&tweet);
    
    // 7. Trait Bound 语法
    notify_bound(&article);
    notify_bound(&tweet);
    
    // 8. 通过 + 指定多个 Trait Bound
    notify_multiple(&article);
    notify_multiple(&tweet);
    
    // 9. 使用 where 简化 Trait Bound
    some_function(5, 10);
    
    // 10. 返回实现了 Trait 的类型
    let tweet = returns_summarizable();
    println!("返回的摘要: {}", tweet.summarize());
    
    // 11. 使用 Trait Bound 有条件地实现方法
    let pair = Pair::new(5, 10);
    pair.cmp_display();
    
    // 12. 为满足 Trait Bound 的任何类型实现 Trait
    // 这在标准库中很常见，例如为实现了 Display 和 PartialOrd 的任何类型实现 ToString
}

// 6. Trait 作为参数
pub fn notify(item: &impl Summary) {
    println!("Breaking news! {}", item.summarize());
}

// 7. Trait Bound 语法
pub fn notify_bound<T: Summary>(item: &T) {
    println!("Breaking news! {}", item.summarize());
}

// 8. 通过 + 指定多个 Trait Bound
use std::fmt::Display;

pub fn notify_multiple(item: &(impl Summary + Display)) {
    println!("Breaking news 222! {}", item.summarize());
}

// 使用 Trait Bound 的语法
pub fn notify_multiple_bound<T: Summary + Display>(item: &T) {
    println!("Breaking news! {}", item.summarize());
}

// 9. 使用 where 简化 Trait Bound
fn some_function<T, U>(_t: T, _u: U) -> i32
where
    T: Display + Clone,
    U: Clone + std::fmt::Debug,
{
    // 函数体
    0
}

// 10. 返回实现了 Trait 的类型
fn returns_summarizable() -> impl Summary {
    Tweet {
        username: String::from("horse_ebooks"),
        content: String::from("of course, as you probably already know, people"),
        reply: false,
        retweet: false,
    }
}

// 11. 使用 Trait Bound 有条件地实现方法
#[derive(Debug)]
struct Pair<T> {
    x: T,
    y: T,
}

impl<T> Pair<T> {
    fn new(x: T, y: T) -> Self {
        Self { x, y }
    }
}

impl<T: Display + PartialOrd> Pair<T> {
    fn cmp_display(&self) {
        if self.x >= self.y {
            println!("最大的是 x = {}", self.x);
        } else {
            println!("最大的是 y = {}", self.y);
        }
    }
}

// 12. 为满足 Trait Bound 的任何类型实现 Trait
// 例如，为实现了 Display 的任何类型实现 ToString
// impl<T: Display> ToString for T {
//     // --snip--
// }